<?php
/**
 * Note: *
 * Date: 2020/2/24
 */
namespace App\Http\Controllers\Admin;

use App\Caches\RoleAccessCache;
use App\Models\RoleAccess;
use App\Services\AuthService;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;

class RoleAccessController extends CurdController
{
    protected string $classModel = RoleAccess::class;

    /**
     * 权限首页(含编辑)
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $authService = new AuthService();
        $access = RoleAccess::pluck('route')->all();
        // $routes = array_flip(array_keys(Route::getRoutes()->getRoutesByName()));

        // 排除 api/ 与 wechat/ 与 anchor/
        $routes = [];
        foreach (Route::getRoutes()->getRoutesByName() as $name => $route) {
            if (Str::startsWith($route->uri(), 'api/') || Str::startsWith($route->uri(), 'wechat/') || Str::startsWith($route->uri(), 'anchor/')) {
                continue;
            }
            $routes[] = $name;
        }
        $routes = array_flip($routes);

        foreach ($routes as $route => $k) {
            // 忽略路由
            if (in_array($route, $authService->getIgnorePermissions())) {
                unset($routes[$route]);
                continue;
            }
            // 忽略路由组 module.action
            if (Str::contains($route, $authService->getIgnorePermissionGroups())) {
                unset($routes[$route]);
                continue;
            }
            // 排除API接口
            if (substr($route, 0, 4) === 'api.') {
                unset($routes[$route]);
                continue;
            }
            // 排除未命名路由
            if (substr($route, -1) === '.') {
                unset($routes[$route]);
                continue;
            }
            $routes[$route] = getRouteTranslate($route);
        }
        return responseData([
            'access' => $access,
            'routes' => $routes,
        ]);
    }

    /**
     * 批量保存需要权限控制的路由
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     * @throws \Throwable
     */
    public function store(Request $request)
    {
        $routes = $request->routes;
        if (in_array('*', $routes)) {
            unset($routes[array_search('*', $routes)]);
        }

        $insertData = [
            [
                'name' => '所有权限',
                'route' => '*'
            ]
        ];
        // 已经定义的路由
        $definedRoutes = array_keys(Route::getRoutes()->getRoutesByName());

        foreach ($routes as $route) {
            // 不存在的路由
            if (!in_array($route, $definedRoutes)) continue;

            $insertData[] = [
                'name' => getRouteTranslate($route),
                'route' => $route,
            ];
        }
        DB::beginTransaction();
        try {
            // 开发阶段直接清空表, 生产阶段采用追加的形式
            //RoleAccess::truncate();
            //RoleAccess::insert($insertData);

            RoleAccess::whereNotIn('route', Arr::pluck($insertData, 'route'))->delete();
            foreach ($insertData as $insert) {
                RoleAccess::updateOrCreate([
                    'route' => $insert['route'],
                ], [
                    'name' => $insert['name'],
                ]);
            }
            // created 或 updated 事件会重复触发, 这里直接设置缓存
            RoleAccessCache::set();
            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            return responseException(__('web.failed'));
        }

        return responseMessage(__('web.success'));
    }

    /**
     * 格式化后的权限列表
     * @param Request $request
     * @param RoleAccess $roleAccess
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function format(Request $request, RoleAccess $roleAccess)
    {
        return responseData($roleAccess->format($this->user->role));
    }
}
